/**
 ***********************************************************************************************************
 * 
 ***********************************************************************************************************
 * @file RBVertexElement.h
 ***********************************************************************************************************/

#ifndef __RBVERTEXELEMENT_H__
#define __RBVERTEXELEMENT_H__

#ifdef  HEADER_ONCE
#pragma HEADER_ONCE
#endif

#ifdef  HEADER_MSG
#pragma HEADER_MSG(RBVertexElement.h)
#endif

/***********************************************************************************************************
 * Includes
 ***********************************************************************************************************/
#include "RBMain/RBRefObject.h"
#include "RBMain/RBMath.h"

/***********************************************************************************************************
 * Forward declarations
 ***********************************************************************************************************/
class RBStream;

/***********************************************************************************************************
 * Classes
 ***********************************************************************************************************/

class RBVertexElement : public RBRefObject
{
public:

    // For convenience, we map Usage and Type to D3D
    // GL mapping will follow

    enum        EUsage 
    {
                VEU_POSITION       = 0,
                VEU_BLENDWEIGHTS,
                VEU_BLENDINDICES,
                VEU_NORMAL,
                VEU_TEXCOORD       = 5,
                VEU_TANGENT,
                VEU_BITANGENT,
                VEU_COLOR          = 10,
                VEU_EXTRA,
                VEU_COUNT
    };

    enum        EType
    {
                VET_FLOAT1        =  0,  // 1D float expanded to (value, 0., 0., 1.)
                VET_FLOAT2        =  1,  // 2D float expanded to (value, value, 0., 1.)
                VET_FLOAT3        =  2,  // 3D float expanded to (value, value, value, 1.)
                VET_FLOAT4        =  3,  // 4D float
                VET_D3DCOLOR      =  4,  // 4D packed unsigned bytes mapped to 0. to 1. range
                VET_UBYTE4        =  5,  // 4D unsigned byte
                VET_SHORT2        =  6,  // 2D signed short expanded to (value, value, 0., 1.)
                VET_SHORT4        =  7,  // 4D signed short
                VET_UBYTE4N       =  8,  // Each of 4 bytes is normalized by dividing to 255.0
                VET_SHORT2N       =  9,  // 2D signed short normalized (v[0]/32767.0,v[1]/32767.0,0,1)
                VET_SHORT4N       = 10,  // 4D signed short normalized (v[0]/32767.0,v[1]/32767.0,v[2]/32767.0,v[3]/32767.0)
                VET_USHORT2N      = 11,  // 2D unsigned short normalized (v[0]/65535.0,v[1]/65535.0,0,1)
                VET_USHORT4N      = 12,  // 4D unsigned short normalized (v[0]/65535.0,v[1]/65535.0,v[2]/65535.0,v[3]/65535.0)
                VET_FLOAT16_2     = 15,  // Two 16-bit floating point values, expanded to (value, value, 0, 1)
                VET_FLOAT16_4     = 16,  // Four 16-bit floating point values
                VET_UNUSED        = 17,  // When the type field in a decl is unused.
                VET_COUNT
    };


    static const uint32 DefaultSize = RBMath::UINT32_MAX;
    static const uint32 MaxStreamCount = 4;

    // Define a Vertex element: size is by default computed automatically, but for padding reason, we allow the user to define its own size
				    RBVertexElement     (uint8 uiStream = 0, EType eType = VET_FLOAT3, EUsage eUsage = VEU_POSITION, uint32 uiSize = DefaultSize);

    virtual        ~RBVertexElement     ();

    uint8           Stream;
    EType           Type;
    EUsage          Usage;
    uint32          Size;

    uint32          GetSize             () const;

    static uint32   GetSize             (EType eType);

    virtual void    Save                (RBStream& kStream);
    virtual void    Load                (RBStream& kStream);

    static const char* GetUsageName     (EUsage eUsage);

};

RBDeclareSmartPointer(RBVertexElement);

/**************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************/
inline uint32 RBVertexElement::GetSize() const
{
    return Size != RBVertexElement::DefaultSize ? Size : GetSize(Type);
}

/**************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************/
inline uint32 RBVertexElement::GetSize(EType eType)
{
    switch(eType)
    {
    case VET_FLOAT1:
    case VET_FLOAT2:
    case VET_FLOAT3:
    case VET_FLOAT4:
        return (eType - VET_FLOAT1 + 1) * sizeof(float32);
    case VET_D3DCOLOR:
    case VET_UBYTE4:
    case VET_SHORT2:
        return 4;
    case VET_SHORT4:
        return 8;
    case VET_UBYTE4N:
    case VET_SHORT2N:
        return 4;
    case VET_SHORT4N:
        return 8;
    case VET_USHORT2N:
        return 4;
    case VET_USHORT4N:
        return 8;
    case VET_FLOAT16_2:
        return 4;
    case VET_FLOAT16_4:
        return 8;
    default:
        RBAssert(false, "Unknown Type");
    }
    return 0;
}

/***********************************************************************************************************/

#endif // __RBVERTEXELEMENT_H__
